package com.fdb.smcts.web.controller;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.rpc.service.GenericService;
import com.fdb.smcts.core.bean.KeyValue;
import com.fdb.smcts.core.cache.CacheManager;
import com.fdb.smcts.core.constant.CacheConstant;
import com.fdb.smcts.core.constant.DataRuleType;
import com.fdb.smcts.core.constant.OperationType;
import com.fdb.smcts.core.util.BeanUtility;
import com.fdb.smcts.core.util.SpringContextUtils;
import com.fdb.smcts.core.util.StringUtil;
import com.fdb.smcts.core.vo.BaseInfo;
import com.fdb.smcts.core.vo.ResourceCtrl;
import com.fdb.smcts.core.vo.UserInfo;

/**
 *
 * Spring mvc Controller父类
 * <p/>
 * 该类主要为了解决通用权限问题，通过权限类型去判断服务提供方调用不同的数据方法
 *
 * @author Cytus_
 * @since 2018-04-24 18:29:23
 * @version 1.0
 */
public abstract class AbstractController implements IController {

	// ServletRequest请求对象
	@Autowired
	protected HttpServletRequest httpRequest;

	@Autowired
	protected HttpServletResponse httpResponse;

	protected static Logger logger = LoggerFactory.getLogger(AbstractController.class);

	// /**
	// * 主要提供数据权限的查询控制, 通过通用的方法，使用hsf的泛型调用来进行查询
	// * @param methodName 代用方法
	// * @param serviceClass 服务的实例对象
	// * @param params 方法的参数
	// * @return
	// */
	// @SuppressWarnings("unchecked")
	// protected final <T> T executeQueryList(String methodName, Object serviceClass, Object[] params) {
	// TODO
	// String uri = this.httpRequest.getRequestURI();
	// logger.debug("当前请求的URI为:"+ uri);
	// UserInfo userInfo = (UserInfo) this.httpRequest.getSession().getAttribute(UserInfo.SEESION_USER_KEY);
	// List<String> roles = new ArrayList<String>();
	// userInfo.getUserRoles().forEach(role -> roles.add(role.getRoleCode()));
	// String dataRuleType = (String) ((GenericService) SpringContextUtils.getBean("sRoleDataRuleService")).$invoke(
	// "getDataRuleType", new String[] { "java.lang.String", "java.util.List" }, new Object[] { uri, roles });
	// try {
	// Method method = getCallMethod(serviceClass, methodName, dataRuleType);
	// String[] paramsType = Arrays.stream(method.getParameters()).map(s ->
	// s.getParameterizedType().getTypeName()).collect(Collectors.toList()).toArray(new String[params.length]);
	//
	// setUserInfoToVO(userInfo, params);
	// GenericService gs = (GenericService) serviceClass;
	//
	// logger.debug("当前调用的服务接口为:"+ serviceClass.getClass()+ ", 调用的方法为:"+ method.getName());
	// Object hsfRtnObj = gs.$invoke(method.getName(), paramsType, params);
	// Object rtnObj = HsfGenericUtils.exchangeRtnData(hsfRtnObj);
	// return (T) rtnObj;
	// } catch (Exception e) {
	// logger.error("当前调用数据权限服务出现异常!", e);
	// }
	//
	// return null;
	// }

	/**
	 * 获取当前用户角色
	 * 
	 * @return
	 */
	public final List<String> getUserRoles() {
		UserInfo userInfo = (UserInfo) this.httpRequest.getSession().getAttribute(UserInfo.SEESION_USER_KEY);
		List<String> roles = new ArrayList<String>();
		userInfo.getUserRoles().forEach(role -> roles.add(role.getRoleCode()));
		return roles;
	}

	/**
	 * 设置用户相关信息到BaseInfo中
	 * 
	 * @param userInfo
	 * @param params
	 */
	private final void setUserInfoToVO(UserInfo userInfo, Object[] params) {
		for (Object object : params) {
			if (object instanceof BaseInfo) {
				BaseInfo baseInfo = (BaseInfo) object;
				baseInfo.setLoginUserId(userInfo.getUserId());
				baseInfo.setLoginUserOrgLocation(userInfo.getOrgInfo().getOrgLocation());
				baseInfo.setLoginUserOrgCode(userInfo.getOrgInfo().getOrgCode());
				baseInfo.setLoginUserLeageOrgCode(userInfo.getLegalOrg().getOrgCode());
			}
		}
	}

	/**
	 * 获得调用方法
	 * 
	 * @param serviceClass
	 * @param methodName
	 * @param dataRuleType
	 * @return
	 */
	private final Method getCallMethod(Object serviceClass, String methodName, String dataRuleType) throws Exception {
		try {
			Method[] methods = serviceClass.getClass().getMethods();
			String mtdName = getCallMethodByDataRuleType(methodName, dataRuleType);
			List<Method> lists = Arrays.stream(methods).filter(m -> m.getName().equals(mtdName)).collect(Collectors.toList());
			if (Objects.nonNull(lists) && lists.size() > 0) {
				return lists.get(0);
			}
		} catch (Exception e) {
			logger.error("当前获取调用方法出现异常!", e);
			throw e;
		}
		return null;
	}

	/**
	 * 获得调用方法名通过权限类型, 该方法dataRuleType不存在或者为空时默认为10
	 * 
	 * @param methodName
	 * @param dataRuleType
	 * @return
	 */
	private final String getCallMethodByDataRuleType(String methodName, String dataRuleType) {
		if (StringUtils.isEmpty(dataRuleType)) {
			dataRuleType = DataRuleType.Owner.getValue();
		}
		String suffix = "";
		if (StringUtils.isNotEmpty(dataRuleType)) {
			for (DataRuleType type : DataRuleType.values()) {
				if (dataRuleType.equals(type.getValue())) {
					suffix = type.toString();
					break;
				}
			}
		}
		return methodName + suffix;
	}

	/**
	 * 设置用户信息对象到VO中
	 * 
	 * @param baseInfo
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final <T> T setUserInfoToVO(BaseInfo baseInfo) {
		UserInfo userInfo = (UserInfo) this.httpRequest.getSession().getAttribute(UserInfo.SEESION_USER_KEY);
		Object[] obj = new Object[] { baseInfo };
		setUserInfoToVO(userInfo, obj);
		return (T) obj[0];
	}

	/**
	 * 获得上下文中用户对象
	 * 
	 * @return
	 */
	public final UserInfo getUserInfo() {
		UserInfo userInfo = (UserInfo) this.httpRequest.getSession().getAttribute(UserInfo.SEESION_USER_KEY);
		return userInfo;
	}

	/**
	 * 机构用户信息翻译
	 * 
	 * @param datas
	 * @param userColumnMapping
	 * @param orgColumnMapping
	 * @return
	 */
	public final <T> Collection<T> displayNames(Collection<T> datas, KeyValue userColumnMapping, KeyValue orgColumnMapping) {
		if (Objects.nonNull(datas) && !datas.isEmpty()) {
			for (T data : datas) {
				if (Objects.nonNull(userColumnMapping)) {
					displayUserName(data, userColumnMapping.getKey(), userColumnMapping.getValue());
				}
				if (Objects.nonNull(orgColumnMapping)) {
					displayOrgName(data, orgColumnMapping.getKey(), orgColumnMapping.getValue());
				}
			}
			;
		}
		return datas;
	}

	/**
	 * 机构用户信息翻译
	 * 
	 * @param datas
	 * @param userColumnMappings
	 * @param orgColumnMappings
	 * @return
	 */
	public final <T> Collection<T> displayNames(Collection<T> datas, Collection<KeyValue> userColumnMappings,
			Collection<KeyValue> orgColumnMappings) {
		if (Objects.nonNull(datas) && !datas.isEmpty()) {
			for (T data : datas) {
				if (Objects.nonNull(userColumnMappings) && !userColumnMappings.isEmpty()) {
					userColumnMappings.forEach(s -> displayUserName(data, s.getKey(), s.getValue()));
				}
				if (Objects.nonNull(orgColumnMappings) && !orgColumnMappings.isEmpty()) {
					orgColumnMappings.forEach(s -> displayOrgName(data, s.getKey(), s.getValue()));
				}
			}
			;
		}
		return datas;
	}

	/**
	 * 翻译机构信息
	 * 
	 * @param data
	 * @param srcColumn
	 * @param targetColumn
	 * @return
	 */
	public final <T> T displayOrgName(T data, String srcColumn, String targetColumn) {
		return displayName(data, srcColumn, targetColumn, CacheConstant.CACHE_KEY_ORG_INFOS, "orgName");
	}

	/**
	 * 翻译用户信息
	 * 
	 * @param data
	 * @param srcColumn
	 * @param targetColumn
	 * @return
	 */
	public final <T> T displayUserName(T data, String srcColumn, String targetColumn) {
		return displayName(data, srcColumn, targetColumn, CacheConstant.CACHE_KEY_USER_INFOS, "userName");
	}

	/**
	 * 机构用户信息翻译
	 * 
	 * @param data
	 * @param srcColumn
	 * @param targetColumn
	 * @param cacheKey
	 * @return
	 */
	private final <T> T displayName(T data, String srcColumn, String targetColumn, String cacheKey, String cacheObjectName) {
		if (Objects.nonNull(data) && StringUtil.isNotEmpty(srcColumn) && StringUtil.isNotEmpty(targetColumn)) {
			try {
				String code = StringUtil.replaceObjNull(BeanUtility.getProptery(data, srcColumn));
				if (StringUtil.isNotEmpty(code)) {
					Object cacheObject = CacheManager.getCacheObject(cacheKey, code);
					if (Objects.nonNull(cacheObject)) {
						Object displayName = BeanUtility.getProptery(cacheObject, cacheObjectName);
						BeanUtility.setProptery(data, targetColumn, displayName);
					}
				}
			} catch (Exception e) {
				logger.error("当前字段：" + srcColumn + ", 目标字段：" + targetColumn + "转换翻译出现异常!", e);
			}
		}
		return data;
	}

	/**
	 * 数据权限验证
	 * 
	 * @param primaryKey
	 * @param configUrl
	 * @param service
	 * @return
	 */
	protected boolean checkOptionalAuthority(Map<String, String> primaryKey, String configUrl, Object service) {
		String cfgUrl = this.httpRequest.getContextPath() + configUrl;
		UserInfo userInfo = (UserInfo) this.httpRequest.getSession().getAttribute(UserInfo.SEESION_USER_KEY);
		List<String> roles = new ArrayList<String>();
		userInfo.getUserRoles().forEach(role -> roles.add(role.getRoleCode()));
		String dataRuleType = (String) ((GenericService) SpringContextUtils.getBean("sRoleDataRuleService")).$invoke("getDataRuleType",
				new String[] { "java.lang.String", "java.util.List" }, new Object[] { cfgUrl, roles });

		// 默认为当前人操作权限
		if (StringUtils.isEmpty(dataRuleType)) {
			dataRuleType = DataRuleType.Owner.getValue();
		}

		primaryKey.put("loginUserId", userInfo.getUserId());
		primaryKey.put("loginUserOrgCode", userInfo.getOrgInfo().getOrgCode());
		primaryKey.put("loginUserLeageOrgCode", userInfo.getLegalOrg().getOrgCode());
		primaryKey.put("loginUserOrgLocation", userInfo.getOrgInfo().getOrgLocation());
		Object rtnObj = ((GenericService) service).$invoke("checkOptionalAuthority", new String[] { "java.util.Map", "java.lang.String" },
				new Object[] { primaryKey, dataRuleType });
		logger.info("数据权限验证成功, 验证数据连接：" + configUrl + ",验证结果：" + rtnObj);
		return Boolean.valueOf(StringUtil.replaceObjNull(rtnObj));
	}

	/**
	 * 检查是否具有创建权限
	 * 
	 * @param rescCode
	 *            资源ID
	 * @return
	 */
	protected boolean checkOperationAuthorityForCreate(String rescCode) {
		return checkOperationAuthority(rescCode, OperationType.Create);
	}

	/**
	 * 检查是否具有修改权限
	 * 
	 * @param rescCode
	 *            资源ID
	 * @return
	 */
	protected boolean checkOperationAuthorityForEdit(String rescCode) {
		return checkOperationAuthority(rescCode, OperationType.Edit);
	}

	/**
	 * 检查是否具有删除权限
	 * 
	 * @param rescCode
	 *            资源ID
	 * @return
	 */
	protected boolean checkOperationAuthorityForDelete(String rescCode) {
		return checkOperationAuthority(rescCode, OperationType.Delete);
	}

	/**
	 * 根据资源Id及操作类型检查是否具有对应的权限
	 * 
	 * @param rescCode
	 *            资源ID
	 * @param type
	 *            操作类型
	 * @return
	 */
	protected boolean checkOperationAuthority(String rescCode, OperationType type) {
		if (StringUtil.isNotEmpty(rescCode)) {
			UserInfo userInfo = (UserInfo) this.httpRequest.getSession().getAttribute(UserInfo.SEESION_USER_KEY);
			List<ResourceCtrl> menuCtrls = userInfo.getMenuCtrls();
			if (menuCtrls != null) {
				for (int i = 0; i < menuCtrls.size(); i++) {
					ResourceCtrl resCtrl = menuCtrls.get(i);
					if (resCtrl != null && resCtrl.getRescCode().equals(rescCode)
							&& resCtrl.getRescActCode().equals(type.getOperationId())) {
						logger.info("操作权限校验成功， 操作资源ID: " + resCtrl.getRescCode() + ",操作码: " + resCtrl.getRescActCode());
						return true;
					}
				}
			}
			logger.error("操作权限校验失败，当前用户操作权限集合：" + menuCtrls);
		}
		return false;
	}

}
